package com.cd.controller;

import com.cd.common.controller.BaseController;
import com.cd.common.domain.AjaxResult;
import com.cd.common.domain.SysUser;
import com.cd.common.dto.UserDto;
import com.cd.common.util.BeanUtils;
import com.cd.system.service.TestService;
//import org.apache.kafka.clients.consumer.ConsumerRecord;
//import org.apache.kafka.clients.consumer.ConsumerRecords;
//import org.apache.kafka.clients.consumer.KafkaConsumer;
//import org.apache.kafka.clients.producer.KafkaProducer;
//import org.apache.kafka.clients.producer.Producer;
//import org.apache.kafka.clients.producer.ProducerRecord;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.UUID;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Description 用于一些简单测试
 * @Author lqq
 * @Date 2023/10/31 14:57
 **/

@RestController
@RequestMapping("/test")
//@Scope("prototype") //可以把该controller变成多例
public class TestController extends BaseController {

    @Autowired
    TestService testService;


    ReentrantLock lock = new ReentrantLock();

    @Autowired
    RedissonClient redissonClient;

//    @Autowired
//    BlobElementRepository blobElementRepository;


    private int num = 0;

    private static final Logger logger = LoggerFactory.getLogger(TestController.class);

//    @RequestMapping(value = "/jpa", method = RequestMethod.GET)
//    public String jpaTest() {
//        return testService.getTestId();
//    }
//
//    // Request mapping for "/mybatis" with GET method
//    @RequestMapping(value = "/mybatis", method = RequestMethod.GET)
//    public String mybatisTest() {
//        return testService.getTestIdUseMybatis();
//    }

    @GetMapping("/hello")
    public String hello() {
        //return "琉球拳欢迎你";

        return "hello"+UUID.randomUUID().toString();
    }
    @RequestMapping(value = "/thread", method = RequestMethod.GET)
    //127.0.0.1:10280/lqq/test/thread
    //线程锁测试
    public String threadTest() {
        logger.info("线程是否有锁{}", lock.isLocked());
        //查看是否有锁
        String threadName = Thread.currentThread().getName();
        logger.info("当前线程为：" + threadName);
        //判断当前线程是否有锁
        //logger.info("线程是否有锁2{}",lock.isLocked());
        logger.info("count:" + lock.getHoldCount());
        logger.info("length:" + lock.getQueueLength());
        if (lock.isLocked()) {
            return "当前正在有人提交";
        }
        //睡十秒
        try {
            lock.tryLock();
            Thread.sleep(5000);//这边是业务
            lock.unlock();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }// finally {
        //lock.unlock();
        //}
        return "提交成功";
    }

    //@Scope("prototype") controller是单例的 方法多例无效
    @RequestMapping(value = "/threadParallel", method = RequestMethod.GET)
    //127.0.0.1:10280/lqq/test/threadParallel
    //并发测试
    public int threadTest3() {
        logger.info("num is {}", num);

        //结论 上锁可以保证值都没问题 性能差点 本质是堆有问题
        //因为controller和service这种都是单例 可以在类上加注解@Scope("prototype") 使其变成多例
        //boot的线程池默认是线程池是200个线程的
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (this) {
            int num = this.num;
            int afterNum = ++this.num;
            logger.info("previous num is {}, final num is {},after num is {}", num, this.num, afterNum);

        }
        return this.num;
    }

    @RequestMapping(value = "/sync/test", method = RequestMethod.GET)
    //127.0.0.1:10280/lqq/test/sync/test
    //异步测试

    public Object threadTest4() throws InterruptedException {
        //Null return value from advice does not match primitive return type for: public int com.lqq.main.controller.TestController.threadTest4()
        //返回了null值，int是无法接收null的,可修改返回值为obj或者void
        //一般发生在环绕后，可以加@Around("updatePoint()")
        String s = testService.testSync();
        Future<String> r1 = testService.testSync1();
        Future<String> r2 = testService.testSync2();
        Future<String> r3 = testService.testSync3();

        //可以实现查看这些是不是均返回
        while (true) {//死循环，每隔2000ms执行一次，判断一下这三个异步调用的方法是否全都执行完了。
            if (r1.isDone() && r2.isDone() && r3.isDone()) {//使用Future的isDone()方法返回该方法是否执行完成
                //如果异步方法全部执行完，跳出循环
                break;
            }
            Thread.sleep(2000);//每隔2000毫秒判断一次
        }
        return "finished";
    }

    //127.0.0.1:10280/lqq/test/seckill/buy/1
    //秒杀
    @RequestMapping(value = "/seckill/buy/{goodId}",
            method = RequestMethod.GET)
    @Transactional
    public AjaxResult seckill(@PathVariable(value = "goodId", required = true) Long goodId) {
        return success(testService.seckill(goodId).getMsg());
    }

    //poi 表格导入导出
    @RequestMapping(value = "/excel/import",
            method = RequestMethod.GET)//http://127.0.0.1:10280/lqq/test/excel/import
    public void excelImport(HttpServletResponse response) throws IllegalAccessException {
        testService.excelImport(response);

    }

    //文件上传
    @RequestMapping(value = "/mutiFileUpload",
            method = RequestMethod.POST)//http://127.0.0.1:10280/lqq/test/
    public void mutiFileUpload(@RequestParam("file") MultipartFile file) throws IllegalAccessException {
        //如果文件夹不存在，创建文件夹
        File folder = new File("d:\\wav");
        if (!folder.exists()) {
            folder.mkdirs();
        }
        //将上传文件的名称记录，存放到固定位置
        File wavFile = new File(folder, file.getOriginalFilename());

        if (!file.isEmpty()) {
            try {
                BufferedOutputStream out = new BufferedOutputStream(
                        new FileOutputStream(wavFile));
                out.write(file.getBytes());
                out.flush();
                out.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                //return "上传失败," + e.getMessage();
            } catch (IOException e) {
                e.printStackTrace();
                //return "上传失败," + e.getMessage();
            }
        } else {
            //return "上传失败，因为文件是空的.";
        }
        //logger.info("地址为"+wavFile.getAbsolutePath());
        //AudioConfig audioConfig = AudioConfig.fromWavFileInput("YourAudioFile.wav");
        return;
    }


    //信号量测试 写原子成员变量应该也差不多 atomic integer
    @RequestMapping("/Semaphore")
    public String testSemaphore() {
        return testService.testSemaphore();
    }

//    @RequestMapping("/kafkaProducer")
//    //kakfa producer
//    public void kafkaProducer(@RequestParam String msg) {
//        Properties props = new Properties();
//        props.put("bootstrap.servers", "localhost:9092");
//        props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
//        props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
//
//        Producer<String, String> producer = new KafkaProducer<>(props);
//        //for (int i = 0; i < 10; i++)
//        producer.send(new ProducerRecord<String, String>("aurora_test", msg, msg));
//
//        producer.close();
//    }
//
//    @RequestMapping("/kafkaConsumer")
//    //kafka consumer
//    public void kafkaConsumer(@RequestParam String... topic) {
//        Properties props = new Properties();
//        props.put("bootstrap.servers", "localhost:9092");
//        props.put("group.id", "test-group");
//        props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
//        props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
//
//        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
//        consumer.subscribe(Arrays.asList(topic));
//        //while (true) {
//        ConsumerRecords<String, String> records = consumer.poll(100);
//        for (ConsumerRecord<String, String> record : records)
//            //System.out.printf("offset = %d, key = %s, value = %s\n", record.offset(), record.key(), record.value());
//            logger.info("offset = {}, key = {}, value = {}", record.offset(), record.key(), record.value());
//        //}
//    }

    //语音识别 发音评估
//    @RequestMapping(value = "/voice",
//            method = RequestMethod.GET)//http://127.0.0.1:10280/lqq/test/voice
//    public SpeechRecognitionResult voice(HttpServletResponse response) throws IllegalAccessException {
//        //创建PronunciationAssessmentConfig对象
////        PronunciationAssessmentConfig pronunciationConfig = new PronunciationAssessmentConfig("",
////                PronunciationAssessmentGradingSystem.HundredMark, PronunciationAssessmentGranularity.Phoneme, false);
////        pronunciationConfig.enableProsodyAssessment();
////        pronunciationConfig.enableContentAssessmentWithTopic("greeting");
//        //创建PronunciationAssessmentConfig对象
//        PronunciationAssessmentConfig pronunciationAssessmentConfig = PronunciationAssessmentConfig.fromJson("{\"referenceText\":\"good morning\",\"gradingSystem\":\"HundredMark\",\"granularity\":\"Phoneme\",\"phonemeAlphabet\":\"IPA\"}");
//
//        //对应的参数
//        SpeechConfig speechConfig = SpeechConfig.fromSubscription("<paste-your-subscription-key>", "<paste-your-region>");
//        AudioConfig audioConfig = AudioConfig.fromWavFileInput("YourAudioFile.wav");
//        SpeechRecognizer speechRecognizer = new SpeechRecognizer(
//                speechConfig,
//                audioConfig);
//
//        pronunciationAssessmentConfig.applyTo(speechRecognizer);
//        Future<SpeechRecognitionResult> future = speechRecognizer.recognizeOnceAsync();
//        SpeechRecognitionResult speechRecognitionResult = null;
//        try {
//            speechRecognitionResult = future.get(30, TimeUnit.SECONDS);
//        } catch (InterruptedException e) {
//            throw new RuntimeException(e);
//        } catch (ExecutionException e) {
//            throw new RuntimeException(e);
//        } catch (TimeoutException e) {
//            throw new RuntimeException(e);
//        }
//
//// The pronunciation assessment result as a Speech SDK object
//        PronunciationAssessmentResult pronunciationAssessmentResult =
//                PronunciationAssessmentResult.fromResult(speechRecognitionResult);
//
//// The pronunciation assessment result as a JSON string
//        String pronunciationAssessmentResultJson = speechRecognitionResult.getProperties().getProperty(PropertyId.SpeechServiceResponse_JsonResult);
//        recognizer.close();
//        speechConfig.close();
//        audioConfig.close();
//        pronunciationAssessmentConfig.close();
//        speechRecognitionResult.close();
//        return speechRecognitionResult;
//
//    }
    @RequestMapping("/test/rLock")
    //测试RLock 互斥锁 以及RMap
    public String RLock() {
        RLock lock = redissonClient.getLock("lock-test");
        Boolean flag = false;
        try {
            //flag=lock.tryLock(3,TimeUnit.SECONDS);//在这个时间内获取锁 获取到返回true
            flag = lock.isLocked();//锁是否被占用
            //isLocked
            //isCurrentLock
            logger.info("i am lqq:{}", flag);
            if (!flag) {
                lock.lock(1, TimeUnit.HOURS);//到达这个时间后自动释放
                Thread.sleep(15000);//业务
                logger.info("sleep over");
                lock.unlock();
                return "流程操作完毕";
            } else {
                logger.info("no sleep");
                return "当前有人在使用";
            }
        } catch (Exception e) {
            logger.error("lock faild :{}", e.getLocalizedMessage());
            lock.unlock();
        } finally {
            //lock.unlock();
        }
        return "";
    }

    @RequestMapping("/test/rLock/unLock")
    //增加锁查看 以及强行释放锁
    public void UnRLock() {
        RedissonClient redissonClient1;
        RLock lock = redissonClient.getLock("lock-test");

        try {
//            lock.lock(1,TimeUnit.HOURS);
//            Thread.sleep(1500000);
            lock.unlock();
        } catch (Exception e) {
            logger.error("lock faild :{}", e.getLocalizedMessage());
        }
    }


    @RequestMapping("/socket")
    public void socket(HttpServletResponse response) throws IllegalAccessException {
        Socket socket = new Socket();
    }

    @RequestMapping("/copyByUtils")
    public void copyByUtils(@RequestParam int sum,
                           @RequestParam int timeNum,
                           @RequestParam boolean flag) throws IllegalAccessException, InterruptedException {
        Long time = System.currentTimeMillis();
        List<SysUser> userList = new LinkedList<>();
        for (int i = 0; i < sum; i++) {
            SysUser user = new SysUser();
            user.setUserName("lqq" + i);
            user.setNickName("lqq" + i);
            user.setCreateBy(i + "pwd");
            user.setUserType(UUID.randomUUID().toString() + i);
            userList.add(user);
        }

        List<UserDto> userDtos = new LinkedList<>();
        for (SysUser user : userList) {
            UserDto userDto = new UserDto();
            BeanUtils.copyProperties(user, userDto);
            userDtos.add(userDto);
        }
        logger.info("beanutils convert ok,consume {} seconds", (System.currentTimeMillis() - time) / 1000);
        Thread.sleep(timeNum);
        if (flag)
            runGC();
        //return userDtos.size();
    }

    @RequestMapping("/copy")
    public void copy(@RequestParam int sum,
                    @RequestParam int timeNum,
                    @RequestParam boolean flag) throws IllegalAccessException, InterruptedException {
        Long time = System.currentTimeMillis();
        List<SysUser> userList = new LinkedList<>();
        for (int i = 0; i < sum; i++) {
            SysUser user = new SysUser();
            user.setUserName("lqq" + i);
            user.setNickName("lqq" + i);
            user.setCreateBy(i + "pwd");
            user.setUserType(UUID.randomUUID().toString() + i);
            userList.add(user);
        }

        List<UserDto> userDtos = new LinkedList<>();
        for (SysUser user : userList) {
            UserDto userDto = new UserDto();
            userDto.setUserName(user.getUserName());
            userDto.setNickName(user.getNickName());
            userDto.setCreateBy(user.getCreateBy());
            userDto.setUserType(user.getUserType());
            userDtos.add(userDto);
        }
        logger.info("manual convert ok,consume {} seconds", (System.currentTimeMillis() - time) / 1000);
        Thread.sleep(timeNum);
        if (flag)
            runGC();
        //return userDtos.size();
    }

    private void runGC() {
        String pid = null;
        Process process1 = null;
        try {
            process1 = Runtime.getRuntime().exec("jps -l");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        BufferedReader reader = new BufferedReader(new InputStreamReader(process1.getInputStream()));
        String line;
        while (true) {
            try {
                if (!((line = reader.readLine()) != null)) break;
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            if (line.contains("LqqApplication")) {
                String[] parts = line.split("\\s+");
                pid = parts[0];
                logger.info("pid is {}",pid);
                runGarbageCollectionCommand(pid);
            }
        }
            }
            private void runGarbageCollectionCommand (String pid){

                String command = "jcmd " + pid + " GC.run";
                Process process = null;
                try {
                    process = Runtime.getRuntime().exec(command);
                    BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
                    String line;
                    while ((line = reader.readLine()) != null) {
                        System.out.println(line);
                    }
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
